Calling Inform from C.

In 2021, Inform gained the ability to generate C code which could be used as
part of a larger program, for example in a framework such as Unity.

@h Introduction.
Users of the Inform UI apps make programs which are usually textual simulations,
and which are in any case sealed boxes running on virtual machines such as Glulx.
Although very creative things have been done to hook those up to other machinery,
usually via Javascript trickery when running those VMs as part of a website, it
is mostly impractical to use those tricks to have Inform 7 work as part of a
bigger program not written in Inform.

However, it is now, as of 2021, possible to use Inform equally well as a
command-line tool and to use it to generate code which can link into a C
program, and indeed it's therefore quite easy to have a hybrid program --
part Inform, part C/C++ (or indeed anything else which can call C functions).
For example, one could imagine a game developed with Unity which uses a
portion of Inform 7 code to manage, say, just world-modelling or text
generation services.

The following documentation covers how to build hybrid Inform-and-C programs.

@h Example makes.
The Inform source repository includes a small suite of examples of such hybrid
programs, stored at:
= (text as ConsoleText)
inform/inform7/Tests/Test Makes/Eg1-C
inform/inform7/Tests/Test Makes/Eg2-C
...
=
These toy programs are automatically built and tested as part of the Inform 7
test suite, but they can also be copied and then experimented with. We'll call
these projects "makes", and indeed each one contains a makefile. Change directory
to it, type |make|, and an executable should appear.

The makefiles assume that you have access to the |clang| C compiler, but |gcc|
could equally be used, or any C-99 compatible tool. The makefiles open with a
reference to the location of the |inform7| installation on your filing system;
so that opening will need to be edited if you move these projects out of
|inform/inform7/Tests/Test Makes/|.

@h Example 1: Hello World.
This first example is not even a hybrid. It compiles the simplest of Basic Inform
programs:
= (text as Inform 7)
To begin:
	say "Hello world.";
=
...by translating it into a C program, which it then compiles, to produce a native
executable. The following shows this working:
= (text as ConsoleText)
$ cd "inform/inform7/Tests/Test Makes/Eg1-C"
$ ls
Eg1.i7			ideal_output.txt	makefile
$ make -silent
$ ls
Eg1			    Eg1-I.o			    ideal_output.txt
Eg1-I.c			Eg1.i7			    makefile
$ ./Eg1
Hello world.
=
|ideal_output.txt| contains the text which the program should print, if it works
correctly: this is used in testing. The make process accomplished the following:
= (text)
 Eg1.i7     source in Inform 7
   |
   | inform7
  \|/
 Eg1-I.c    source in C
   |
   | clang (acting as C compiler)
  \|/
 Eg1-I.o    C object file
   |
   | clang (acting as linker)
  \|/
  Eg1       native executable
=
As with all of the examples, |make run| runs the program, building it if necessary;
and |make clean| removes the files generated by the build process, returning the
directory to its mint condition. In this case, that means deleting |Eg1-I.c|,
|Eg1-I.o| and |Eg1|. Note the filenaming convention: the |-I| in the name of, say,
|Eg1-I.c| is supposed to signal that the file was derived from an Inform original.

The makefile for Example 1 is simple, and in a full build it runs the following:
= (text as ConsoleText)
$ make
../../../Tangled/inform7 -silence -basic -format=C -o Eg1-I.c Eg1.i7
clang -g -std=c99 -c -I ../../../Internal/Miscellany -o Eg1-I.o Eg1-I.c
clang -g -o Eg1 Eg1-I.o
=
All three tools compile silently if no errors occur, though in the case of //inform7//
that's only because |-silence| was asked for. |-basic| indicates that this is a
Basic Inform program, which is not asked to contain a command parser, for example.
|-format=C| makes the output a C program rather than an Inform 6 one, of course.

The |-I ../../../Internal/Miscellany| switch when using |clang| as C compiler
tells it that this directory should be in the search path for |#include| files.
This is needed so that:
= (text as C)
#include "inform7_clib.h"
=
will work. This header file is supplied in every Inform installation at:
= (text)
inform7/Internal/Miscellany/inform7_clib.h
=

@h Example 2: Hello Hello.
This time we begin with both a C program and an Inform program, both of which
want to say hello: we want to compile these into a single executable. Now the
makefile has an extra step:
= (text)
	Eg2.c		 Eg2.i7     source in C and Inform 7 respectively
	  |			    |
	  |			    | inform7
	  |			   \|/
	  |			 Eg2-I.c    source in C
	  |			    |
	  |	clang	    | clang (acting as C compiler)
	 \|/		   \|/
	Eg2.o		 Eg2-I.o    C object files
	  |			    |
	  +------+------+
		     |
		     | clang (acting as linker)
		    \|/
		    Eg2       		native executable
=
That will be the basic plan for all the remaining examples too, so we'll stop
with these diagrams. Here |Eg2.c| is the C part of our source code, and is not
to be confused with |Eg2-I.c|, which is the conversion to C of the Inform part
of our source. Each produces an object file, and the link unites these into a
single executable.

The Inform source reads:
= (text as Inform 7)
To begin:
	say "Hello from the Inform source."
=
The C source could be very easy too:
= (text as C)
#include "inform7_clib.h"

int main(int argc, char **argv) {
	printf("Hello from the C source code.\n");
	i7process_t proc = i7_new_process();
	i7_run_process(&proc);
	return 0;
}
=
When run, this produces:
= (text as ConsoleText)
Hello from the C source code.
Hello from the Inform source.
=
Note that the C program is the one in command here: in particular, it contains
|main|. That means of course that |Eg2-I.c| must not include a |main| function,
or the linking stage will throw an error; whereas |Eg1-I.c|, in the previous example,
did have to include |main|. So clearly something must be different about the
command to generate C from Inform this time.

This issue is resolved by tweaking the |-format| requested. Whereas the makefile
for example 1 asked |inform7| for |-format=C|, the makefile for example 2 asks it
for |-format=C/no-main|. The |no-main| tells the part of Inform which generates C
code not to make a |main| of its own, and so all is well. |-format=C/main| is
the default arrangement, to which |-format=C| is equivalent.

@ The type |i7process_t| is used for an "Inform process".[1] A single C program can
contain any number of these, and indeed could call them independently from
multiple threads at the same time: but they are all instances of the same Inform
program running, each with its own independent state and data. So, for example,
two different Inform processes will have two different values for the same Inform
variable name. In effect, they are isolated, independent virtual machines, each
running a copy of the same program.

It is essential to create a process as shown, with a call to |i7_new_process|.
Once created, though, the same process can be run multiple times. If we had
written,
= (text as C)
	i7process_t proc = i7_new_process();
	i7_run_process(&proc);
	i7_run_process(&proc);
=
then the result would have been:
= (text as ConsoleText)
Hello from the C source code.
Hello from the Inform source.
Hello from the Inform source.
=

[1] Strictly speaking, typedef names ending |_t| are reserved for use by the
POSIX standard, so this is a sin, but really, I don't see POSIX ever needing names
prefixed |i7|, and besides, everybody does it.

@ A note about thread safety. Suppose the C program runs multiple threads. Then:

(a) It is perfectly thread-safe for two or more threads to each be running
Inform processes simultaneously, but
(b) They must be different |i7process_t| objects, and
(c) They do not share any data: each process has its own data. If there is an
Inform variable called "favourite colour", for example, two different |i7process_t|
processes running at the same time will have two different values of this.

Note that all |i7process_t| instances are running the same Inform program. You
cannot, at present, link multiple different Inform programs into the same C
program.

@ Formally speaking, |i7_run_process| returns the entire Inform program to its
end, and then returns an exit code: 0 if that program exited cleanly, and 1
if it halted with a fatal error, for example through dividing by zero, or
failing a memory allocation. In that event, an error message will be printed
to |stderr|.

So, for the sake of tidiness, the full |Eg2.c| reads:
= (text as C)
#include "inform7_clib.h"

int main(int argc, char **argv) {
	printf("Hello from the C source code.\n");
	i7process_t proc = i7_new_process();
	int exit_code = i7_run_process(&proc);
	if (exit_code == 1) {
		printf("*** Fatal error: halted ***\n");
		fflush(stdout); fflush(stderr);
	}
	return exit_code;
}
=
Example 2 is in fact so simple that it is impossible for the exit code to be
other than 0, but checking the exit code is good practice.

@h Example 3: HTML Receiver.
This third example demonstrates a "receiver" function. The text printed by
Inform 7 can be captured, processed, and in general handled however the C
program would like. This is done by assigning a receiver to the process,
after it is created, but before it is run:
= (text as C)
	i7process_t proc = i7_new_process();
	i7_set_process_receiver(&proc, my_receiver, 1);
=
Here |my_receiver| is a function. The default receiver looks like this:
= (text as C)
void i7_default_receiver(int id, inchar32_t c, char *style) {
	if (id == I7_BODY_TEXT_ID) fputc(c, stdout);
}
=
This receives the text printed by the Inform process, one character at a time.

(*) The |id| is a "window ID", a detail which doesn't matter to a Basic Inform
project -- it will always in fact be |I7_BODY_TEXT_ID|. For a full Inform project
such as an IF work, it might be any of three possibilities:
(-*) |I7_BODY_TEXT_ID|, the main transcript of text in the story;
(-*) |I7_STATUS_TEXT_ID|, the "status line" header at the top of a traditional
Terminal-window-style presentation of this text;
(-*) |I7_BOX_TEXT_ID|, a quotation printed in a box which overlies the main text.

(*) The |style| is a stylistic markup. It will always be a valid C string, of
length at most 256, but is often the empty C string and of length 0, meaning
"this is plain text with no styling applied".
(-*) The three main styles are |italic|, |bold|, |reverse| and |fixedpitch|.
(-*) Plain styling and these three can all be combined with a "fixed-pitch type"
request, thus: |fixedpitch|, |italic,fixedpitch|, |bold,fixedpitch|, |reverse,fixedpitch|.

As can be seen, the default receiver ignores all text not sent to the main window,
and ignores all styling even on that.

The significance of the 1 in the call |i7_set_process_receiver(&proc, my_receiver, 1)|
is that it asked for text to be sent to the receiver encoded as UTF-8. This in fact
is the default receiver's arrangement, too. Call |i7_set_process_receiver(&proc, my_receiver, 0)|
to have the characters arrive raw as a series of unencoded Unicode code-points.

In Example 3, the Inform source is:
= (text as Inform 7)
To begin:
	say "Hello & [italic type]welcome[roman type] from <Inform code>!"
=
The example receiver function converts this to HTML:
= (text as ConsoleText)
<html><body>
Hello &amp; <span class="italic">welcome</span> from &lt;Inform code&gt;!
</html></body>
=
The word "welcome" here was printed with the style |"italic"|; all else was
plain.

This example just prints the result, of course, but a receiver function could
equally opt to bottle up the text for use later on.

@h Example 4: CSS Receiver.
Example 4 builds on Example 3 but allows arbitrary named CSS styles to applied,
i.e., it is not limited to bold and italic markup.

The C program from Example 3 is unchanged, but the Inform program does something
more interesting. We're going to need to do something unusual here, and define
two new phrases using inline definitions as raw Inter code, written in Inform 6
notation:
= (text as Inform 7)
To style text with (T - text):
	(- style {T}; -).
=
The result of this will be something which Inform 6 would not compile, because
in I6 the only legal uses of |style| are |style bold| and so on: there is no
legal way for |style| to be followed by an arbitrary value, as it is here. But
Inform 6 will not be compiling this: Inform will convert |style V;| directly to
the Inter statement |!style V|, which will then be translated to C as the function
call |i7_styling(proc, 2, V)| -- and that function, in our library of C code
supporting Inform, can handle any textual value of |V|.

With that bit of fancy footwork out of the way, we can make a pair of text
substitutions |[style NAME]| and |[end style]|, with the possible range of
styles enumerated by name, like so:
= (text as Inform 7)
A text style is a kind of value.
The text styles are decorative, calligraphic and enlarged.

To say style as (T - text style):
	style text with "[T]".

To say end style:
	(- style roman; -).
=

Finally, then, we can have:
= (text as Inform 7)
To begin:
	say "[style as enlarged]Hello[end style] & [style as calligraphic]welcome[end style] from <Inform code>!"
=
And the result is:
= (text as ConsoleText)
<html><body>
<span class="enlarged">Hello</span> &amp; <span class="calligraphic">welcome</span> from &lt;Inform code&gt;!
</html></body>
=

@h Example 5: Sender.
It's now time to make a traditional piece of interactive fiction with Inform,
with a world model, a command parser, and the standard command-and-response
play loop. But we will call this from C, and decide the commands there.

This means a small change to the makefile, to remove |-basic| from the options
for |inform7|, since we're no longer confining ourselves to Basic Inform.

The I7 source could be that for almost any game -- any of the examples in the
Inform documentation would do. The C source is more interesting here. Just as
an |i7_process| can be given a "receiver" function, which receives text from
it, it can also be given a "sender" which sends text to it. Thus:
= (text as C)
	i7process_t proc = i7_new_process();
	i7_set_process_sender(&proc, the_quitter);
=
Here |the_quitter| is the following sender function:
= (text as C)
char *the_quitter(int count) {
	char *cmd = "";
	switch (count) {
		case 0: cmd = "quit"; break;
		case 1: cmd = "y"; break;
	}
	printf("%s\n", cmd);
	return cmd;
}
=
This must return a C string (that is, a |char *| pointer to a null-terminated
sequence of non-control ASCII characters) which represents a whole line of
imaginary "typing" by the player. The argument |count| counts upwards from 0,
incrementing after each call to the sender. So the effect of |the_quitter|
is to simulate the effect of typing "quit" and then "y".

The resulting transcript of play looks like this:
= (text as ConsoleText)
Sir Arthur Evans, hero and archeologist, invites you to explore...

Welcome
An Interactive Fiction
Release 1 / Serial number 210917 / Inform 7 v10.1.0 / D

Jarn Mound

>quit
Are you sure you want to quit? y
=
Thus, the "y" is needed in order to respond to the followup question "Are you
sure...?".

Note that the process is stalled while waiting for the sender to return a
line of input: it's not working away in the background. The default sender
uses |getchar|, from the C standard library, to receive a genuinely typed
command terminated by a new-line.

@h Example 6: Directing actions.
More radically, it's possible to take textual input away entirely, by setting
the sender function to |NULL|.

What will happen then is that the |i7_run_process| function will return at
the point where a command would have been requested. The C function can then
trigger whatever actions it wants, in the world model, without the need to
feed a textual command back to I7 which would then be parsed into actions.
In this example we do just that, and also examine and modify the data belonging
to the I7 program from C.

The story, such as it is:
= (text as Inform 7)
Jarn Mound is a room.

Age is a kind of value. The ages are modern, antique and ancient. A thing has
an age. The age of a thing is usually modern.

In the Mound is a Linear B tablet. The tablet is ancient. The player is wearing
a watch.

The meaning is a text that varies. The meaning is "4 oxen, 1 broken tripod table."

Instead of examining the watch:
	say "It is approximately [time of day]."

Report examining the tablet:
	say "It is [age of tablet], and translates to '[meaning]'."

When play begins:
	now the command prompt is "";
	say "Sir Arthur Evans, hero and archeologist, invites you to explore..."
=

In this example the C program is:
= (text as C)
#include "inform7_clib.h"
#include "inform7_symbols.h"

int main(int argc, char **argv) {
	i7process_t proc = i7_new_process();
	i7_set_process_sender(&proc, NULL);
	if (i7_run_process(&proc) == 0) {
		i7word_t t = i7_read_variable(&proc, i7_V_the_time);
		printf("[C program reads 'time of day' as %d]\n", t);
		i7word_t A = i7_read_prop_value(&proc, i7_I_Linear_B_tablet, i7_P_age);
		printf("[C program reads 'age of Linear B tablet' as %d]\n", A);
		i7_try(&proc, i7_A_Take, i7_I_Linear_B_tablet, 0);	
		i7_try(&proc, i7_A_Inv, 0, 0);
		i7_write_variable(&proc, i7_V_the_time, 985);
		i7_try(&proc, i7_A_Examine, i7_I_watch, 0);	
		i7_write_variable(&proc, i7_V_the_time, 995);
		i7_try(&proc, i7_A_Examine, i7_I_watch, 0);	
		i7_write_prop_value(&proc, i7_I_Linear_B_tablet, i7_P_age, i7_I_modern);
		i7_try(&proc, i7_A_Examine, i7_I_Linear_B_tablet, 0);	
		return 0;
	} else {
		printf("*** Fatal error: halted ***\n");
		fflush(stdout); fflush(stderr);
		return 1;
	}
}
=
Note that a header file called |inform7_symbols.h| is included. This defines
useful constants like |i7_A_Take| (for the "taking" action) and |i7_I_Linear_B_tablet|
(for the object called "Linear B tablet"). But where did this header come from?

The answer is that this file can optionally be created when //inform7// is
generating C. In Example 5 we ran Inform with |-format=C/no-main|; this time
we use |-format=C/no-main/symbols-header|. This also needs a subtle change to
the makefile logic; the difference being that |Eg6-C.o| is now dependent on
|Eg6-I.c|. This forces |make| to create |Eg6-I.c|, and as a byproduct |inform7_symbols.h|,
before compiling |Eg6-C.c| to make |Eg6-C.o|.
= (text)
Eg6: Eg6-C.o Eg6-I.o
	$(LINK) -o Eg6 Eg6-C.o Eg6-I.o

Eg6-C.o: Eg6.c Eg6-I.c
	$(CC) -o Eg6-C.o Eg6.c

Eg6-I.o: Eg6-I.c
	$(CC) -o Eg6-I.o Eg6-I.c

Eg6-I.c: Eg6.i7
	$(INFORM) -format=C/no-main/symbols-header -o Eg6-I.c Eg6.i7
=

Anyway, the result of this is:
= (text as ConsoleText)
Sir Arthur Evans, hero and archaeologist, invites you to explore...

Welcome
An Interactive Fiction
Release 1 / Serial number 210919 / Inform 7 v10.1.0 / D

Jarn Mound
You can see a Linear B tablet here.

[C program reads 'time of day' as 540]
[C program reads 'age of Linear B tablet' as 3]
Taken.

You are carrying:
  a Linear B tablet
  a watch (being worn)

It is approximately 4:25 pm.

It is approximately 4:35 pm.

You see nothing special about the Linear B tablet.

It is modern, and translates to "4 oxen, 1 broken tripod table.".
=
Here we see a run of responses, as if to unheard commands: those of course
are the actions sent directly to the process by |i7_try|.

The data inside the Inform program is represented in C by values of the type
|i7word_t|. (In practice, this is probably a 32-bit integer, but it's best to
make no assumptions.) Inform at run-time is typeless, so it's up to the C
programmer to know what is meant. For example, we know the result of the call
|i7_read_variable(&proc, i7_V_the_time)| will be an integer from 0 to 1439,
because the variable has kind "time" in Inform 7, and this is how Inform stores
times of day (in minutes since midnight).

@ Example 6 used most of the following suite of functions for looking at or
altering the Inform data.

First, some functions which can only be applied to instances of |object|:

(*) |i7_move(&proc, obj, to)| moves object |obj| to become a child of |to|;
(*) |i7_parent(&proc, obj)| returns the current parent object of |obj|;
(*) |i7_child(&proc, obj)| returns its first child;
(*) |i7_sibling(&proc, obj)| returns the next child of the same parent as |obj|.

Second, functions to look at global variables:

(*) |i7_read_variable(&proc, var)| returns the current value of the variable |var|;
(*) |i7_write_variable(&proc, var, val)| sets the value to |val|.

Note that where variables are created by kits such as WorldModelKit, their ID
constants have names based on the names they have in those kits: thus |i7_V_the_time|
refers to the time of day, not |i7_V_time_of_day|. Browsing |inform7_symbols.h| 
will usually make things clear, anyway.

Finally, properties of objects can similarly be read or written:

(*) |i7_read_prop_value(&proc, obj, prop)| returns the current value of property
|prop| for the object |obj|;
(*) |i7_write_prop_value(&proc, obj, prop, val)| sets it to |val|.

If you need access to other data inside the Inform program, it's better to
process it at the Inform end. These functions are just a convenience for what's
most often needed.

@h Example 7: Reading and writing lists and texts from C.
Following on from Example 6, suppose we want to deal with Inform variables (or
property values) containing texts, or lists -- these, for instance:
= (text as Inform 7)
The meaning is a text that varies. The meaning is "4 oxen, 1 broken tripod table."

The dial is a list of numbers that varies. The dial is { 3, 6, 9, 12 }.
=
If we call, say, |i7_read_variable| on |i7_V_meaning| then the return value is
an |i7word_t| which is, in fact, an address somewhere in the Inform process memory.
What are we to do with this? In fact, it's easy to convert to and from a C string:
= (text as C)
char *M = i7_read_string(&proc, i7_read_variable(&proc, i7_V_meaning));
printf("[C program reads 'meaning' as %s]\n", M);
i7_try(&proc, i7_A_Examine, i7_I_Linear_B_tablet, 0);	
i7_write_string(&proc, i7_read_variable(&proc, i7_V_meaning),
	"the goddess of the winds beckons you!");
i7_try(&proc, i7_A_Examine, i7_I_Linear_B_tablet, 0);	
=
And this produces the following:
= (text as ConsoleText)
[C program reads 'meaning' as 4 oxen, 1 broken tripod table.]
It is ancient, and translates to "4 oxen, 1 broken tripod table.".

It is ancient, and translates to "the goddess of the winds beckons you!".
=
Here we repeat the action of examining the tablet: we examine once before changing
the "meaning" and once after.

Similarly for lists:
= (text as C)
int L = 0;
i7word_t *D = i7_read_list(&proc, i7_read_variable(&proc, i7_V_dial), &L);
printf("[C program reads 'dial' as");
for (int i=0; i<L; i++) printf(" %d", D[i]);
printf("]\n");
i7_try(&proc, i7_A_Examine, i7_I_watch, 0);
D[0] = 2;
D[1] = 10;
i7_write_list(&proc, i7_read_variable(&proc, i7_V_dial), D, 2);
i7_try(&proc, i7_A_Examine, i7_I_watch, 0);	
=
which produces:
= (text as ConsoleText)
[C program reads 'dial' as 3 6 9 12]
It is approximately 9:00 am, according to a dial showing 3, 6, 9 and 12.

It is approximately 9:00 am, according to a dial showing 2 and 10.
=

@ The following functions are available:

(*) |i7_read_string(proc, T)| returns a newly-allocated null terminated C
string with the contents of the text T. If you're doing a lot of this, you
may want to |free| the returned string pointer. If memory allocation fails,
the Inform process halts with a fatal error, so you need not check yourself.
(*) |i7_write_string(proc, T, string)| sets the text T to the null-terminated
C string given; if this is |NULL|, T is set to the empty text.
(*) |i7_read_list(proc, L, length)| returns a newly-allocated C array of |i7word_t|
values, which are the current contents of the Inform list (whose address is) |L|.
If |length| is given, it should be a pointer to an |int|, in which is stored the
length of the list. If you're doing a lot of this, you may want to |free| the
returned array pointer. If memory allocation fails, the Inform process halts
with a fatal error, so you need not check yourself.
(*) |i7_write_list(proc, L, array, length)| sets the Inform list |L| to have
length |length| and contents given by |array[0], ..., array[length-1]|, where
the |array| must be of |i7word_t| values. If |array| is |NULL| or |length| is 0,
then |L| is left as the empty list.

@h Example 8: Direct function calls between C and Inform programs.
This final example shows how the C and Inform programs can call each other's
functions, albeit with some minor restrictions.

First, we have a C function called |collatz|, and we want to call it from Inform.
This function must have a prototype like so:
= (text as C)
i7word_t collatz(i7process_t *proc, i7word_t x) {
	...
}
=
In particular, it must receive a single value (other than the process) and
return a single value.

At the Inform side, we need to give this a wrapper as a phrase. Say, this:
= (text as Inform 7)
To call C collatz function with (N - a number):
	(- external__collatz({N}); -).
=
Note that we've written that definition inline, and that the function is here
called |external__collatz|. (The prefix |external__| signals that the function
won't be found in the Inter code generated by Inform; without that, Inform
would throw a problem message.) With that done, the Inform code:
= (text as Inform 7)
	call C collatz function with 17;
=
will perform |collatz(proc, 17)|, as expected.

@ Now we want to do this the other way round: have C make a function call into
Inform. The function to call this time is the one implied by this phrase declaration:
= (text as Inform 7)
To run the Collatz algorithm on (N - a number):
	...
=
And the C needed to call this is simple enough:
= (text as C)
	i7_F_run_the_collatz_algorithm_on_X(17);
=
|i7_F_run_the_collatz_algorithm_on_X| is in fact a defined name: see the
include file |inform7_symbols.h| for a list of the functions available for
calling like this. (Phrases defined inline cannot be called, because they
are not functions.)

The Inform phrase used can also return a value ("To decide what..."), and
can have any number of arguments, so this is less restrictive than the
first way round.

@ Example 8 shows both of these mechanisms working, with control tossed back
and forth between the two programs. They are pretending to be two people, Mr C
and Mrs I, playing a simple number game: the winner is the one who reaches 1.
= (text as ConsoleText)
MR C: My friend Mrs I calls my attention to 17, so I triple and add one.
MRS I: I have heard Mr C tell that 52 is an interesting number. And so I halve.
MR C: My friend Mrs I calls my attention to 26, so I divide by two.
MRS I: I have heard Mr C tell that 13 is an interesting number. And so I treble and add 1.
MR C: My friend Mrs I calls my attention to 40, so I divide by two.
MRS I: I have heard Mr C tell that 20 is an interesting number. And so I halve.
MR C: My friend Mrs I calls my attention to 10, so I divide by two.
MRS I: I have heard Mr C tell that 5 is an interesting number. And so I treble and add 1.
MR C: My friend Mrs I calls my attention to 16, so I divide by two.
MRS I: I have heard Mr C tell that 8 is an interesting number. And so I halve.
MR C: My friend Mrs I calls my attention to 4, so I divide by two.
MRS I: I have heard Mr C tell that 2 is an interesting number. And so I halve.
MR C: My friend Mrs I calls my attention to 1, so I win! Haha!
=
Here the function calls reached 11 deep: Inform called C which called Inform
which called C which... and so on. But everything then terminated cleanly.
